package com.sktk.keepAccount.aop;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sktk.keepAccount.annotation.Decrypt;
import com.sktk.keepAccount.common.core.exception.BaseException;
import com.sktk.keepAccount.common.core.exception.SystemErrorType;
import com.sktk.keepAccount.common.core.util.AESUtil;
import com.sktk.keepAccount.common.core.vo.Result;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 请求参数解密
 * http://www.zzvips.com/article/187109.html
 * https://www.cnblogs.com/shamo89/p/16498217.html
 */
@ControllerAdvice
public class DecryptRequest extends RequestBodyAdviceAdapter {

    @Override
    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return methodParameter.hasMethodAnnotation(Decrypt.class) || methodParameter.hasParameterAnnotation(Decrypt.class);
    }

    @Override
    public HttpInputMessage beforeBodyRead(final HttpInputMessage inputMessage, MethodParameter parameter,
                                           Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {

        if (targetType == null) {
            throw new BaseException(SystemErrorType.BUSINESS_ERROR, "sdf");
        }

        try {

            // 获取请求数据byte
            byte[] body = new byte[inputMessage.getBody().available()];

            inputMessage.getBody().read(body);

            // 转化为字符串
            String bodyStr = new String(body);

            // 转换为对象
            JSONObject bodyObj = JSONObject.parseObject(bodyStr);

            // 定义无需解密参数
            List<String> noDecryptFiled = Arrays.asList("appClient", "channel", "version", "token", "projectId");

            // 定义解密后参数map
            HashMap<String, String> decryptParam = new HashMap<>();

            // 循环请求对象
            for (Map.Entry<String, Object> stringObjectEntry : bodyObj.entrySet()) {

                String key = stringObjectEntry.getKey();
                String value = stringObjectEntry.getValue().toString();

                // 如果是开发环境，无需解密
                if (Result.getEnv().equals("dev")) {
//                    decryptParam.put(key, value);
//                    continue;
                }

                // 若是无需解密参数，直接put进decryptParam
                if (noDecryptFiled.contains(stringObjectEntry.getKey())) {
                    decryptParam.put(key, value);
                    continue;
                }

                // 解密
                decryptParam.put(key, AESUtil.decrypt(value, Result.SALT));
            }

            // 转换为byte
            byte[] decrypt = JSON.toJSONString(decryptParam).getBytes(StandardCharsets.UTF_8);

            final ByteArrayInputStream bais = new ByteArrayInputStream(decrypt);
            return new HttpInputMessage() {
                @Override
                public InputStream getBody() throws IOException {
                    return bais;
                }

                @Override
                public HttpHeaders getHeaders() {
                    return inputMessage.getHeaders();
                }
            };

        } catch (Throwable e) {
            throw new BaseException(SystemErrorType.BUSINESS_ERROR, "参数解密失败，请检查");
        }

    }
}